﻿using System;
using System.Collections.Generic;
using System.Web;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

using Infrastructure.NetExtensions;
using Infrastructure.Diagnostics;
using TempEmployees.DAL;

namespace TempEmployees.BLL.Forms
{
    public class ProduceForms
    {
        protected static readonly string DATE_FORMAT = "d/M/yyyy";

        // directories
        public static readonly string SOURCE_DIR = HttpContext.Current.Server.MapPath(@"~\BLL\Forms");
        public static readonly string ROOT_DIR = HttpContext.Current.Server.MapPath(@"~\ProducedForms");

        protected static void ProduceForm(string form, object source, string path)
        {
            if (!File.Exists(path))
            {
                string content;
                string template = Path.Combine(SOURCE_DIR, string.Format("{0}.htm", form));
                using (TextReader tr = new StreamReader(template))
                {
                    content = tr.ReadToEnd();
                }

                content = FillContent(content, source);

                SaveForm(content, path);
            }

            SendForm(path);
        }

        protected static string FillContent(string content, object source)
        {
            string pattern = @"(\$\(([a-zA-Z]+[a-zA-Z.]*[a-zA-Z]),([0-9]+)\))";
            return Regex.Replace(content, pattern, (match) =>
            {
                try
                {
                    string matched = match.Groups[0].ToString();
                    string property = match.Groups[2].ToString();
                    int size = int.Parse(match.Groups[3].ToString());

                    object value = null;
                    if (!SpecialProperties(property, ref value)) value = source.GetNonIndexedPropertyValue(property);
                    if (value == null) return matched;

                    string text;
                    if (value is DateTime || value is DateTime?) text = ((DateTime)value).ToString(DATE_FORMAT);
                    else text = value.ToString();

                    return AdjustText(text, size);
                }
                catch (Exception e)
                {
                    Logger.Error(Logger.ExceptionMessage(e));
                    return string.Empty;
                }
            });
        }

        protected static void SaveForm(string content, string path)
        {
            if (!Directory.Exists(Path.GetDirectoryName(path))) Directory.CreateDirectory(Path.GetDirectoryName(path));
            using (TextWriter tr = new StreamWriter(path, false, Encoding.UTF8))
            {
                tr.Write(content);
            }
        }

        protected static void SendForm(string path)
        {
            string attachment = string.Format("attachment; filename={0}", Path.GetFileName(path));
            HttpResponse response = HttpContext.Current.Response;
            response.ClearContent();
            response.AddHeader("content-disposition", attachment);
            response.ContentType = "text/HTML";
            response.WriteFile(path);
            response.End();
        }

        protected static string AdjustText(string text, int size)
        {
            if (size == 0) return text;
            string SPACE = "&nbsp;";
            StringBuilder builder = new StringBuilder();
            if (text.Length >= size)
            {
                builder.Append(SPACE);
                builder.Append(text);
                builder.Append(SPACE);
            }
            else
            {
                int left = (int)((size - text.Length) / 2) + 1;
                int right = (size - text.Length) / 2;
                for (int i = 0; i < right; i++) builder.Append(SPACE);
                builder.Append(text);
                for (int i = 0; i < right; i++) builder.Append(SPACE);
            }
            return builder.ToString();
        }

        protected static bool SpecialProperties(string property, ref object value)
        {
            string[] parts = property.Split('.');
            if (parts[0].CompareTo("Special") != 0 || parts.Length != 2) return false;

            switch (parts[1])
            {
                case "DateTime":
                    value = DateTime.Now;
                    break;
                default:
                    return false;
            }
            return true;
        }

        public static void ProduceMosadRequest(Assignment assignment)
        {
            string path = Path.Combine(ROOT_DIR, "MosadRequests", string.Format("MosadRequest_Assignment_{0}.htm", assignment.ID));
            ProduceForm("MosadRequest", assignment, path);
        }

        public static void ProduceEmployeeDetails(Employee employee)
        {
            string formId = (employee.CurrentAssignment != null) ? employee.CurrentAssignment.ID.ToString() : DateTime.Now.ToString("M_yy");
            string path = Path.Combine(ROOT_DIR, "EmployeeDetails", string.Format("EmployeeDetails_Employee_{0}_{1}.htm", employee.ID, formId));
            ProduceForm("EmployeeDetails", employee, path);
        }

        public static void ProduceMosadStudent(Assignment assignment)
        {
            string path = Path.Combine(ROOT_DIR, "MosadStudents", string.Format("MosadStudent_Assignment_{0}.htm", assignment.ID));
            ProduceForm("MosadStudent", assignment, path);
        }

        public static void ProducePrintExtension(Assignment newAssignment)
        {
            string path = Path.Combine(ROOT_DIR, "PrintExtensions", string.Format("PrintExtension_Assignment_{0}.htm", newAssignment.ID));
            ProduceForm("PrintExtension", newAssignment, path);
        }

        public static void ProducePrintNewEmployee(Assignment assignment)
        {
            string path = Path.Combine(ROOT_DIR, "PrintNewEmployees", string.Format("PrintNewEmployee_Assignment_{0}.htm", assignment.ID));
            ProduceForm("PrintNewEmployee", assignment, path);
        }
    }
}